package com.huxi.lang.file.xls;

import static com.huxi.lang.text.MessageFormatter.format;

import java.sql.Timestamp;
import java.time.DateTimeException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.Objects;

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;

import com.huxi.lang.object.VList;
import com.huxi.lang.type.BooleanParseException;

public class TableRow implements VList {

	private Row row;
	private ZoneOffset offset;

	protected TableRow(Row row, ZoneOffset offset) {
		this.row = Objects.requireNonNull(row);
		this.offset = Objects.requireNonNull(offset);
	}

	public Row getRow() {
		return row;
	}

	void setRow(Row row) {
		this.row = Objects.requireNonNull(row);
	}

	public int getRowNum() {
		return row.getRowNum();
	}

	public int getLastRowNum() {
		return row.getSheet().getLastRowNum();
	}

	public int getSheetSize() {
		return row.getSheet().getLastRowNum() + 1;
	}

	@Override
	public int size() {
		return (int) row.getLastCellNum();
	}

	@Override
	public boolean isSizeMutable() {
		return false;
	}

	@Override
	public Object get(int index) {
		return XlsUtils.getCellValue(row.getCell(index));
	}

	@Override
	public void set(int index, Object value) throws ArrayIndexOutOfBoundsException {
		Cell cell = row.getCell(index);
		if (cell == null) {
			try {
				cell = row.createCell(index);
			} catch (IllegalArgumentException en) {
				throw new ArrayIndexOutOfBoundsException("超过工作表格最大长度");
			}
		}
		XlsUtils.setCellValue(cell, value);
	}

	@Override
	public Object getAndSet(int index, Object value) throws ArrayIndexOutOfBoundsException {
		Cell cell = row.getCell(index);
		if (cell == null) {
			try {
				cell = row.createCell(index);
			} catch (IllegalArgumentException en) {
				throw new ArrayIndexOutOfBoundsException("超过工作表格最大长度");
			}
		}
		return XlsUtils.getAndSetCellValue(cell, value);
	}

	/**
	 * 校验行头与自身是否一致
	 * 
	 * @param expected 行头
	 * @param message  失败信息
	 * @throws RuntimeException 不一致
	 */
	public void checkHeadEquals(String[] expected, String message) throws RuntimeException {
		if (expected.length != size()) {
			throw new RuntimeException(format("{}非期望结构，表格列数不相等[{}]: [{}]", message, expected.length, size()));
		}
		for (int i = 0; i < expected.length; i++) {
			String ss = getStringValue(i);
			if (ss != null) {
				ss = ss.trim();
			}
			if (!expected[i].equals(ss)) {
				throw new RuntimeException(format("{}非期望结构，表格第{}列字段不一致: {}", message, i, ss));
			}
		}
	}

	public String getStringValue(int index) {
		return XlsUtils.getCellStringValue(row.getCell(index));
	}

	public Timestamp getDateValue(int index) throws DateTimeException {
		return XlsUtils.getCellDateValue(row.getCell(index), offset);
	}

	public Timestamp getDateTimeValue(int index) throws DateTimeException {
		return XlsUtils.getCellDateTimeValue(row.getCell(index), offset);
	}

	public LocalDate getLocalDateValue(int index) throws DateTimeException {
		return XlsUtils.getCellLocalDateValue(row.getCell(index), offset);
	}

	public LocalDateTime getLocalDateTimeValue(int index) throws DateTimeException {
		return XlsUtils.getCellLocalDateTimeValue(row.getCell(index), offset);
	}

	public Boolean getBooleanValue(int index) throws BooleanParseException {
		return XlsUtils.getCellBooleanValue(row.getCell(index));
	}

	public boolean getBooleanPrimitiveValue(int index) throws BooleanParseException {
		return XlsUtils.getCellBooleanPrimitiveValue(row.getCell(index));
	}

	public Double getDoubleValue(int index) throws NumberFormatException {
		return XlsUtils.getCellDoubleValue(row.getCell(index));
	}

	public double getDoublePrimitiveValue(int index) throws NumberFormatException {
		return XlsUtils.getCellDoublePrimitiveValue(row.getCell(index));
	}

	public Float getFloatValue(int index) throws NumberFormatException {
		return XlsUtils.getCellFloatValue(row.getCell(index));
	}

	public float getFloatPrimitiveValue(int index) throws NumberFormatException {
		return XlsUtils.getCellFloatPrimitiveValue(row.getCell(index));
	}

	public Long getLongValue(int index) throws NumberFormatException {
		Double vv = getDoubleValue(index);
		return vv != null ? vv.longValue() : null;
	}

	public long getLongPrimitiveValue(int index) throws NumberFormatException {
		Double vv = getDoubleValue(index);
		return vv != null ? vv.longValue() : 0L;
	}

	public Integer getIntegerValue(int index) throws NumberFormatException {
		Double vv = getDoubleValue(index);
		return vv != null ? vv.intValue() : null;
	}

	public int getIntPrimitiveValue(int index) throws NumberFormatException {
		Double vv = getDoubleValue(index);
		return vv != null ? vv.intValue() : 0;
	}

	public Short getShortValue(int index) throws NumberFormatException {
		Double vv = getDoubleValue(index);
		return vv != null ? vv.shortValue() : null;
	}

	public short getShortPrimitiveValue(int index) throws NumberFormatException {
		Double vv = getDoubleValue(index);
		return vv != null ? vv.shortValue() : 0;
	}

	public Byte getByteValue(int index) throws NumberFormatException {
		Double vv = getDoubleValue(index);
		return vv != null ? vv.byteValue() : null;
	}

	public byte getBytePrimitiveValue(int index) throws NumberFormatException {
		Double vv = getDoubleValue(index);
		return vv != null ? vv.byteValue() : 0;
	}

}
